//
//  HeartBeat.m
//  gdemm
//
//  Created by yongwu on 15/12/28.
//  Copyright © 2015年 goldensoft. All rights reserved.
//
#include "gdsm3.h"
#import "HeartBeat.h"
#import "DeviceInfo.h"
#import "UserDefaultsUtil.h"
#import "ApiSupport.h"
#import "PolicyManager.h"
#import "InboxManager.h"
#import "MessageManager.h"
#import "RemoteAlarm.h"
#import "RemoteLocation.h"
#import "ExamineManager.h"
#import "KeyChain.h"
#import "ObjCHiredis.h"
@interface HeartBeat()
@property(strong,nonatomic) GCDAsyncUdpSocket *mHeartSocket;
@property(strong,nonatomic) GCDAsyncSocket *mRedisSocket;
@property(nonatomic) BOOL mRelogined; // 上线后再次登录认证(如果未走登录流程直接上线了，应认证一次)
@property (nonatomic,assign) BOOL mOnline;
@property(strong,nonatomic) NSMutableArray<OnlineStateListener> *mListeners;
@property (assign,nonatomic) NSInteger failCount;
@property(strong,nonatomic)ObjCHiredis *redis;
@property(strong,nonatomic)NSThread * currentThread ;
@end


@implementation HeartBeat
static HeartBeat* _instance = nil;

- (instancetype)init
{
    
    if (self = [super init]) {
        [self creatUdpConnect];
        [self createRedisConnect];
        _mOnline = false;
        _mRelogined = false;
        _mListeners = [[NSMutableArray<OnlineStateListener> alloc]init];
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self sendHeart];
        });
        //[self sendRedis];
    }
    return self;
}

+(instancetype) shareInstance
{
    static dispatch_once_t onceToken ;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init] ;
    }) ;
    
    return _instance ;
}
//消息通知
- (void)showNotification{
    UILocalNotification *localNote = [[UILocalNotification alloc]init];
    localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:1.0];
    localNote.timeZone = [NSTimeZone defaultTimeZone];
    localNote.alertBody = @"您有新消息,点击此处查看消息";
    localNote.alertAction = @"这是锁屏界面的信息";
    localNote.alertLaunchImage = @"Default";
    localNote.soundName = @"/System/Library/Audio/UISounds/RingerChanged.caf";//@"messagevoiceprompt.mp3";
    UIApplication *app = [UIApplication sharedApplication];
    [app presentLocalNotificationNow:localNote];
    
}

- (void)createRedisConnect{
    dispatch_queue_t dQueue = dispatch_queue_create("redis tcp socket", NULL);
    self.mRedisSocket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dQueue];
    //[_mRedisSocket connectToHost:[[UserDefaultsUtil shareInstance] getString:LC_SERVADDR] onPort:REDIS_PORT error:nil];
    
}
-(void)creatUdpConnect{
    dispatch_queue_t dQueue = dispatch_queue_create("client udp socket", NULL);
    _mHeartSocket = [[GCDAsyncUdpSocket alloc]initWithSocketQueue:dQueue];
    NSError *erro;
    [_mHeartSocket enableBroadcast:YES error:&erro];
    [_mHeartSocket setIPv6Enabled:false];
    [_mHeartSocket setIPv4Enabled:TRUE];
    [_mHeartSocket receiveOnce:&erro];
    [_mHeartSocket setDelegateQueue:dispatch_get_main_queue()];
    self.mHeartSocket.delegate =self;
    [_mHeartSocket bindToPort:HEARTBEAT_PORT error:&erro];
    [self.mHeartSocket receiveOnce:nil];
    
}

-(void)sendBackToHost:(NSString *)ip port:(uint16_t)port{

    NSInteger tmpValue = [[UserDefaultsUtil shareInstance]getInt:LC_LASTEXAMINERESULT];
            
    NSString *userGuid = [[UserDefaultsUtil shareInstance]getString:LC_USERGUID];
    NSString *devUnique = [KeyChain getUDID];
    NSString *ipaddr = [DeviceInfo getIpAddress];
    NSString *mac = [DeviceInfo getMacAddress];
    NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
    [dict setValue:0 forKey:@"type"];
    [dict setValue:userGuid forKey:@"userGuid"];
    [dict setValue:devUnique forKey:@"devUnique"];
    [dict setValue:ipaddr forKey:@"ip"];
    [dict setValue:mac forKey:@"mac"];
    [dict setValue:[NSString stringWithFormat:@"%ld",tmpValue] forKey:@"examineState"];
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil];
            [self.mHeartSocket sendData:jsonData toHost:ip port:port withTimeout:-1 tag:0];
   
         
}
-(void)sendHeart
{
    while (true) {
        NSDate *date = [NSDate dateWithTimeIntervalSinceNow:3.0];
        [NSThread sleepUntilDate:date];
        if ([[UserDefaultsUtil shareInstance]getBool:LC_LOGINED]) {
            [self sendBackToHost:[[UserDefaultsUtil shareInstance] getString:LC_SERVADDR] port:HEARTBEAT_PORT];
            [self.mHeartSocket receiveOnce:nil];
        }
    }
}

-(void)sendRedis{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while (YES) {
            NSDate *date = [NSDate dateWithTimeIntervalSinceNow:1.0];
            [NSThread sleepUntilDate:date];
            if ([[UserDefaultsUtil shareInstance]getBool:LC_LOGINED]) {
                [self.mRedisSocket connectToHost:[[UserDefaultsUtil shareInstance] getString:LC_SERVADDR] onPort:REDIS_PORT error:nil];
                self.redis = [ObjCHiredis redis:[[UserDefaultsUtil shareInstance] getString:LC_SERVADDR] on:[NSNumber numberWithInt:REDIS_PORT]];
                NSString *channel = [NSString stringWithFormat:@"subscribe %@",[[UserDefaultsUtil shareInstance]getString:LC_USERGUID]];
                [self.redis command:channel];
    
                self.currentThread =  [NSThread currentThread];
                NSArray *message = [self.redis getReply];
                
                if (message != nil && message.count == 3) {
                    NSString *info = message[2];
                    if ([info containsString:@"remotePosition"]) {
                        [[RemoteLocation getInstance]startLocation];
                    }
                }
                
            }
        }
        
    });
}
#pragma mark -GCDAsyncUdpSocketDelegate

-(void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContex
{
    if ([self isLogined]) {
        [self onLine:YES];
    }
    //取得发送发的ip和端口
    NSString *ip = [GCDAsyncUdpSocket hostFromAddress:address];
    uint16_t port = [GCDAsyncUdpSocket portFromAddress:address];
    NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    HRLog(@"[%@:%u]%@",ip, port,s);
    [self parseResponseWithData:data];
}
#pragma makr 心跳UDP长连接代理方法
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag{
    //HRLog(@"消息发送成功！-----");
}
-(void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock{
    HRLog(@"连接已关闭！-----");

}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error{
    [self sendBackToHost:[[UserDefaultsUtil shareInstance] getString:LC_SERVADDR] port:HEARTBEAT_PORT];
    HRLog(@"发送失败!");

}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError *)error{
    HRLog(@"连接失败");
}

- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError *)error{
    HRLog(@"意外关闭");
}

#pragma mark redis长连接代理方法

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{
    

}

-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
    //[self.mRedisSocket connectToHost:[[UserDefaultsUtil shareInstance] getString:LC_SERVADDR] onPort:REDIS_PORT error:nil];
}

//解析发送心跳包获取到的数据
- (void)parseResponseWithData:(NSData *)data{
    NSError *error;
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
    if (error) {
        HRLog(@"%@",error);
        return;
    }
    NSInteger type = [dict[@"type"] intValue];
    if (PACKET_TYPE_HEARTBEAT == type) {
        [self processHeartbeatResponseWithDic:dict];
        
    }else if (PACKET_TYPE_NOTIFY == type){
        [self processNotifyWithDic:dict];
    
    }else if (PACKET_TYPE_ACTION == type){
        [self processActionWithDic:dict];
        
    }
    
}

//在线的解析
- (void)processHeartbeatResponseWithDic :(NSDictionary *)dict{
    NSString *result  = dict[@"result"];
    if ([result isEqualToString:@"offline"] || [result isEqualToString:@"failed"]) {
        [self offline];
        if ([result isEqualToString:@"failed"]) {
            [[UserDefaultsUtil shareInstance]saveBoolConfig:LC_HBFAILED :YES];
        }else{
            [[UserDefaultsUtil shareInstance]saveBoolConfig:LC_HBOFFLINE :YES];
        }
        
        int nacState = [dict[@"nacState"] intValue];
        [[UserDefaultsUtil shareInstance]saveIntConfig:LC_NACSTATE :nacState ];
       
    }
    
}

//策略更新&&文件分发&&消息通知
- (void)processNotifyWithDic:(NSDictionary *)dict{
    NSString *notify_id = dict[@"notify_id"];
    NSString *notify_type = dict[@"notify_type"];
    if ([NOTIFY_TYPE_POLICYUPDATE isEqualToString:notify_type]) {
        [[PolicyManager getInstance]updatePolicyWithsilent:YES];
    }else if ([NOTIFY_TYPE_FILESYNC isEqualToString:notify_type]){
    
        [[InboxManager getInstance]getUndowloadedFileCount:YES];
    }else if ([NOTIFY_TYPE_MESSAGE isEqualToString:notify_type]){
    
        [self showNotification];
        [[MessageManager getInstance]loadCloundFileInfo:NO];
        HRLog(@"你有新短消息,请注意查收");
        NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
        [dict setValue:@PACKET_TYPE_NOTIFY forKey:@"type"];
        [dict setValue:notify_id forKey:@"notify_id"];
        NSData *jsData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil];
        
        [self.mHeartSocket sendData:jsData toHost:[[UserDefaultsUtil shareInstance] getString:LC_SERVADDR] port:HEARTBEAT_PORT withTimeout:-1 tag:0];
    }
}

//实时动作
- (void)processActionWithDic:(NSDictionary *)dict{
    NSInteger action = 0;
    action = [dict[@"action"] intValue];
    if (ACTION_TYPE_RING == action) {
        //响铃
        [RemoteAlarm remoteAlarm];
        
    }else if (ACTION_TYPE_LOCATION == action){
        //定位
        [[RemoteLocation getInstance]startLocation];
        
    
    }else if (ACTION_TYPE_EXAMINE == action){
        [[ExamineManager getInstance] startExamine];
    
    }
    
}

-(BOOL)isLogined{
    return  [[UserDefaultsUtil shareInstance]getBool:LC_LOGINED];
}
-(BOOL)reLogin{
    
    NSString *userName = [[UserDefaultsUtil shareInstance]getString:LC_USERNAME];
    NSString *passWd = [[UserDefaultsUtil shareInstance] getString:LC_PASSWORD];
    if ([StringUtil isEmpty:userName]||[StringUtil isEmpty:passWd]) {
        return false;
    }
    NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
    const char *str = [passWd UTF8String];
    long len = strlen(str);
    unsigned const  char out_bf[65];
    sm3_buffer((void *)str, (int)len, (void *)out_bf, 32);
    [dict setValue:userName forKey:@"username"];
    [dict setValue:[NSString stringWithUTF8String:(void *)out_bf] forKey:@"password"];
    [dict setValue:[DeviceInfo getIpAddress] forKey:@"loginIp"];
    [dict setValue:[KeyChain getUUID] forKey:@"serial"];
    NSString *s = [HttpUtil buildUrl:[ApiSupport getUserLoginUrl] WithParams:dict];
    NSURL *url = [NSURL URLWithString:s];
    ASIHTTPRequest *request = [[ASIHTTPRequest alloc]initWithURL:url];
    [request startSynchronous];
    NSError *error;
    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:request.rawResponseData options:NSJSONReadingMutableLeaves error:&error];
    if (error != nil) {
        return false;
    }
    NSString *result = (NSString*)[dic objectForKey:@"result"];
    if (![result isEqual:@"success"]) {
        [[UserDefaultsUtil shareInstance]saveBoolConfig:LC_LOGINED :NO];
        [[UserDefaultsUtil shareInstance]saveBoolConfig:LC_HBOFFLINE :YES];
        return false;
    }
    return true;
}

-(void)onLine:(BOOL)onLine{
    if (![self isLogined]) {
        return;
    }
    if (_mOnline == onLine) {
        return;
    }
    if (onLine) {
        if ([[UserDefaultsUtil shareInstance] getBool:LC_MANUALLOGIN]&&_mRelogined){
            if (![self reLogin]) {
                return;
            }
            _mRelogined = true;
        }
    }
    _mOnline = onLine;

    for (id<OnlineStateListener> listener in _mListeners) {
        [listener onLine:onLine];
    }
}

+(BOOL)isOnline{
    if (_instance == nil) {
        return false;
    }
    return _instance.mOnline;
}
-(void)offline{
    [self onLine:false];
    [[UserDefaultsUtil shareInstance]saveBoolConfig:LC_LOGINED :NO];
    [self.currentThread cancel];
    //[self.redis close];
    
}

-(void)addOnlineStateListener:(id<OnlineStateListener>)listener{
    if (![_mListeners containsObject:listener]) {
        [_mListeners addObject:listener];
        
    }
}

- (void)close{
    [self.redis close];
}
@end
